/*!
 * \file charconv.hpp
 * \brief 字符编码转换工具类集合
 * 
 * \details 提供跨平台的字符编码转换功能，包括：
 *          - UTF-8和本地字符集之间的双向转换
 *          - URL编码和解码
 *          - ASCII字符检测
 *          - 跨平台兼容性支持（Windows/Unix）
 *          
 *          支持的转换：
 *          - UTF-8 ↔ 本地字符集（Windows ANSI/Unix GBK）
 *          - URL编码/解码
 *          - 自动检测纯ASCII字符，优化转换性能
 *          
 *          在国际化应用和Web交互中非常重要，确保中文等
 *          多字节字符的正确处理和传输。
 */
#pragma once
#include <stdlib.h>
#include <string>
#ifdef _MSC_VER
#include <windows.h>
#else
#include <iconv.h>
#endif

/*!
 * \brief UTF-8字符串转换为本地字符集的转换器
 * 
 * \details RAII风格的字符串转换工具，特点：
 *          - 自动检测纯ASCII字符，无需转换
 *          - Windows平台：UTF-8 → Unicode → ANSI
 *          - Unix平台：UTF-8 → GBK（使用iconv）
 *          - 自动内存管理，异常安全
 *          - 支持隐式转换为const char*
 *          
 *          使用场景：
 *          - 显示UTF-8编码的中文文本
 *          - 与本地API交互
 *          - 文件路径处理
 */
class UTF8toChar
{
public :
	/*!
	 * \brief 构造函数（C字符串版本）
	 * \param utf8_string UTF-8编码的输入字符串
	 */
	UTF8toChar(const char *utf8_string)
	{
		init(utf8_string);
	}

	/*!
	 * \brief 构造函数（std::string版本）
	 * \param utf8_string UTF-8编码的输入字符串
	 */
	UTF8toChar(const std::string& utf8_string)
	{
		init(utf8_string.c_str());
	}

	/*!
	 * \brief 初始化转换过程
	 * \param utf8_string UTF-8编码的输入字符串
	 * 
	 * \details 转换逻辑：
	 *          1. 空指针检查
	 *          2. 空字符串处理
	 *          3. 纯ASCII检测（优化）
	 *          4. 多字节字符转换
	 *          
	 *          Windows: UTF-8 → UTF-16 → ANSI
	 *          Unix: UTF-8 → GBK（iconv）
	 */
	void init(const char *utf8_string)
	{
		if (0 == utf8_string)
			t_string = 0;
		else if (0 == *utf8_string)
		{
			needFree = false;
			t_string = ("");
		}
		else if ( isPureAscii(utf8_string))
		{
			needFree = false;
			t_string = (char *)utf8_string;
		}
		else
		{
			// Either TCHAR = Unicode (2 bytes), or utf8_string contains non-ASCII characters.
			// Needs conversion
			needFree = true;

			// Convert to Unicode (2 bytes)
			std::size_t string_len = strlen(utf8_string);
			std::size_t dst_len = string_len * 2 + 2;
#ifdef _MSC_VER
			wchar_t *buffer = new wchar_t[string_len + 1];
			MultiByteToWideChar(CP_UTF8, 0, utf8_string, -1, buffer, string_len + 1);
			buffer[string_len] = 0;

			t_string = new char[string_len * 2 + 2];
			WideCharToMultiByte(CP_ACP, 0, buffer, -1, t_string, dst_len, 0, 0);
			t_string[string_len * 2 + 1] = 0;
			delete[] buffer;
#else
			iconv_t cd;
			t_string = new char[dst_len];

			cd = iconv_open("gbk", "utf8");
			if (cd != 0)
			{
				memset(t_string, 0, dst_len);
				iconv(cd, (char**)&utf8_string, &string_len, &t_string, &dst_len);
				iconv_close(cd);
				t_string[dst_len] = '\0';
			}
#endif
		}
	}

	/*!
	 * \brief 隐式转换为C字符串
	 * \return 转换后的本地字符集字符串
	 */
	operator const char*()
	{
		return t_string;
	}

	/*!
	 * \brief 获取C字符串指针
	 * \return 转换后的本地字符集字符串
	 */
	const char* c_str()
	{
		return t_string;
	}

	/*!
	 * \brief 析构函数，自动释放内存
	 */
	~UTF8toChar()
	{
		if (needFree)
			delete[] t_string;
	}

private :
	char *t_string;      ///< 转换后的字符串指针
	bool needFree;       ///< 是否需要释放内存标志

	/*!
	 * \brief 检测字符串是否为纯ASCII
	 * \param s 待检测的字符串
	 * \return 纯ASCII返回true，否则返回false
	 * 
	 * \details 通过检查每个字节的最高位来判断：
	 *          - ASCII字符：0xxxxxxx
	 *          - 多字节字符：1xxxxxxx
	 */
	bool isPureAscii(const char *s)
	{
		while (*s != 0) { if (*(s++) & 0x80) return false; }
		return true;
	}

	//disable assignment
	UTF8toChar(const UTF8toChar &rhs);
	UTF8toChar &operator=(const UTF8toChar &rhs);
};

/*!
 * \brief 本地字符集转换为UTF-8的转换器
 * 
 * \details RAII风格的反向字符串转换工具，特点：
 *          - 自动检测纯ASCII字符，无需转换
 *          - Windows平台：ANSI → Unicode → UTF-8
 *          - Unix平台：GBK → UTF-8（使用iconv）
 *          - 自动内存管理，异常安全
 *          - 支持隐式转换为const char*
 *          
 *          使用场景：
 *          - 网络传输中文数据
 *          - JSON/XML数据生成
 *          - 跨平台数据交换
 */
class ChartoUTF8
{
public :
	/*!
	 * \brief 构造函数（std::string版本）
	 * \param str 本地字符集编码的输入字符串
	 */
	ChartoUTF8(const std::string& str)
	{
		init(str.c_str());
	}

	/*!
	 * \brief 构造函数（C字符串版本）
	 * \param t_string 本地字符集编码的输入字符串
	 */
	ChartoUTF8(const char *t_string)
	{
		init(t_string);
	}

	/*!
	 * \brief 初始化转换过程
	 * \param t_string 本地字符集编码的输入字符串
	 * 
	 * \details 转换逻辑：
	 *          1. 空指针检查
	 *          2. 空字符串处理
	 *          3. 纯ASCII检测（优化）
	 *          4. 多字节字符转换
	 *          
	 *          Windows: ANSI → UTF-16 → UTF-8
	 *          Unix: GBK → UTF-8（iconv）
	 */
	void init(const char *t_string)
	{
		if (0 == t_string)
			utf8_string = 0;
		else if (0 == *t_string)
		{
			utf8_string = "";
			needFree = false;
		}
		else if (isPureAscii((char *)t_string))
		{
			utf8_string = (char *)t_string;
			needFree = false;
		}
		else
		{

			needFree = true;

			std::size_t string_len = strlen(t_string);
			std::size_t dst_len = string_len * 3 + 1;
#ifdef _MSC_VER		

			// Convert to Unicode if not already in unicode.
			wchar_t *w_string = new wchar_t[string_len + 1];
			MultiByteToWideChar(CP_ACP, 0, t_string, -1, w_string, string_len + 1);
			w_string[string_len] = 0;

			// Convert from Unicode (2 bytes) to UTF8
			utf8_string = new char[dst_len];
			WideCharToMultiByte(CP_UTF8, 0, w_string, -1, utf8_string, dst_len, 0, 0);
			utf8_string[string_len * 3] = 0;

			if (w_string != (wchar_t *)t_string)
				delete[] w_string;
#else
			iconv_t cd;
			utf8_string = new char[dst_len];

			cd = iconv_open("utf8", "gbk");
			if (cd != 0)
			{
				memset(utf8_string, 0, dst_len);
				iconv(cd, (char**)&t_string, &string_len, &utf8_string, &dst_len);
				iconv_close(cd);
				utf8_string[dst_len] = '\0';
			}
#endif
		}
	}

	/*!
	 * \brief 隐式转换为C字符串
	 * \return 转换后的UTF-8字符串
	 */
	operator const char*()
	{
		return utf8_string;
	}

	/*!
	 * \brief 获取C字符串指针
	 * \return 转换后的UTF-8字符串
	 */
	const char* c_str() const
	{
		return utf8_string;
	}

	/*!
	 * \brief 析构函数，自动释放内存
	 */
	~ChartoUTF8()
	{
		if (needFree)
			delete[] utf8_string;
	}

private :
	char *utf8_string;   ///< 转换后的UTF-8字符串指针
	bool needFree;       ///< 是否需要释放内存标志

	/*!
	 * \brief 检测字符串是否为纯ASCII
	 * \param s 待检测的字符串
	 * \return 纯ASCII返回true，否则返回false
	 */
	bool isPureAscii(const char *s)
	{
		while (*s != 0) { if (*(s++) & 0x80) return false; }
		return true;
	}

	//disable assignment
	ChartoUTF8(const ChartoUTF8 &rhs);
	ChartoUTF8 &operator=(const ChartoUTF8 &rhs);
};


/*!
 * \brief URL编码器
 * 
 * \details 将字符串转换为URL安全的编码格式，特点：
 *          - 保留ASCII字母、数字和安全字符
 *          - 空格转换为%20
 *          - 其他字符转换为%XX十六进制格式
 *          - 支持隐式转换为const char*
 *          
 *          编码规则：
 *          - ASCII字母数字：保持原样
 *          - 空格：转换为%20
 *          - 其他字符：转换为%XX（XX为十六进制值）
 *          
 *          使用场景：
 *          - HTTP请求参数编码
 *          - URL查询字符串处理
 *          - Web表单数据提交
 */
class URLEncode
{
public:
	/*!
	 * \brief 构造函数，执行URL编码
	 * \param src 待编码的源字符串
	 * 
	 * \details 编码过程：
	 *          1. 遍历每个字符
	 *          2. ASCII安全字符：直接保留
	 *          3. 空格：转换为%20
	 *          4. 其他字符：转换为%XX格式
	 */
	URLEncode(const char* src)
	{ 
		char hex[] = "0123456789ABCDEF";  

		for (unsigned int i = 0; i < strlen(src); ++i)
		{  
			const char cc = src[i];  
			if (isPureAscii(&cc))  
			{  
				if (cc == ' ')  
				{  
					encoded_string += "%20";  
				}  
				else 
					encoded_string += cc;  
			}  
			else 
			{  
				unsigned char c = static_cast<unsigned char>(src[i]);
				encoded_string += '%';  
				encoded_string += hex[c / 16];  
				encoded_string += hex[c % 16];
			}  
		}  
	}
	
	/*!
	 * \brief 隐式转换为C字符串
	 * \return 编码后的URL字符串
	 */
	operator const char*(){return encoded_string.c_str();}

private:
	/*!
	 * \brief 检测字符是否为纯ASCII
	 * \param s 待检测的字符
	 * \return 纯ASCII返回true，否则返回false
	 */
	bool isPureAscii(const char *s)
	{
		while (*s != 0) { if (*(s++) & 0x80) return false; }
		return true;
	}

private:
	std::string encoded_string;  ///< 编码后的字符串
};

/*!
 * \brief URL解码器
 * 
 * \details 将URL编码的字符串还原为原始格式，特点：
 *          - 处理%XX十六进制编码
 *          - 处理+号（空格的另一种编码）
 *          - 验证十六进制字符的有效性
 *          - 支持隐式转换为const char*
 *          
 *          解码规则：
 *          - %XX：转换为对应的字节值
 *          - +：转换为空格
 *          - 其他字符：保持原样
 *          
 *          使用场景：
 *          - HTTP请求参数解析
 *          - URL查询字符串处理
 *          - Web表单数据接收
 */
class URLDecode
{
public:
	/*!
	 * \brief 构造函数，执行URL解码
	 * \param src 待解码的URL编码字符串
	 * 
	 * \details 解码过程：
	 *          1. 遍历每个字符
	 *          2. +号：转换为空格
	 *          3. %XX：验证并转换为字节值
	 *          4. 其他字符：直接保留
	 *          
	 *          注意：包含中文注释的字符检查逻辑，
	 *          用于判断哪些字符需要解码
	 */
	URLDecode(const char* src)
	{ 
		int hex = 0;  
		for (unsigned int i = 0; i < strlen(src); ++i)
		{  
			switch (src[i])  
			{  
			case '+':  
				decoded_string += ' ';  
				break;  
			case '%':  
				if (isxdigit(src[i + 1]) && isxdigit(src[i + 2]))  
				{
					std::string hexStr;
					hexStr += src[i+1];
					hexStr += src[i+2];
					hex = strtol(hexStr.c_str(), 0, 16);
					//字母数字[0-9a-zA-Z]，一些符号[$-_.+!*'(),] 以及某些保留字符[$&+,/:;=?@]  
					//都可以不经编码直接用于URL  
					if (!((hex >= 48 && hex <= 57) || //0-9  
						(hex >=97 && hex <= 122) ||   //a-z  
						(hex >=65 && hex <= 90) ||    //A-Z  
						//一些符号以及保留字符[$-_.+!*'(),]  [$&+,/:;=?@]  
						hex == 0x21 || hex == 0x24 || hex == 0x26 || hex == 0x27 || hex == 0x28 || hex == 0x29 
						|| hex == 0x2a || hex == 0x2b|| hex == 0x2c || hex == 0x2d || hex == 0x2e || hex == 0x2f 
						|| hex == 0x3A || hex == 0x3B|| hex == 0x3D || hex == 0x3f || hex == 0x40 || hex == 0x5f 
						))  
					{  
						decoded_string += char(hex);
						i += 2;  
					}  
					else decoded_string += '%';  
				}else {  
					decoded_string += '%';  
				}  
				break;  
			default:
				decoded_string += src[i];  
				break;  
			}  
		}  
	}

	/*!
	 * \brief 隐式转换为C字符串
	 * \return 解码后的原始字符串
	 */
	operator const char*(){return decoded_string.c_str();}

private:
	std::string decoded_string;  ///< 解码后的字符串
};